package utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Iterator;
import java.util.Scanner;

import weka.core.Instances;
import weka.core.converters.CSVLoader;
import weka.filters.Filter;
import weka.filters.unsupervised.attribute.NumericToNominal;

public class DataManipulation {

	private Instances dataset = null;
	private String dataset_path = null;
	
	// base classifiers settings
	String [] baseClassifiers = null;
	String [][] options = null;

	public DataManipulation(String pathDataset,String type) {
		this.dataset_path = pathDataset;
		if(type == "arff")
			this.load_from_ARFF();
		else if(type == "csv")
			this.load_from_CSV();
	}

	// load data
	public void load_from_ARFF() {
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(dataset_path));
			dataset = new Instances(reader);
			reader.close();
			// setting class attribute
			dataset.setClassIndex(dataset.numAttributes() - 1);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO: handle exception
			System.out.println("IOexception error");
			e.printStackTrace();
		}
		

	}
	
	public void load_from_CSV() {
		CSVLoader loader = new CSVLoader();
		try {
			loader.setSource(new File(dataset_path));
			dataset = loader.getDataSet();
			// setting class attribute
			dataset.setClassIndex(dataset.numAttributes() - 1);
			// Tranforma a classe em atributo nominal
		    NumericToNominal filter = new NumericToNominal();
		    filter.setAttributeIndices("last"); 
		    try {
		    	filter.setInputFormat(dataset);
				dataset = Filter.useFilter(dataset, filter);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				System.out.println("error while setting NumericToNominal on: load_from_CSV(); classe: DataManipulation");
				e.printStackTrace();
			}
//		    String name = dataset.relationName();
//		    dataset.setRelationName(name);
		    
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
//		Instances data = loader.getDataSet();
	}

	public Instances getDataset() {
		return dataset;
	}
	
	public Double getMean(List<Double> values){
		Double media = new Double(0.0);
		
		Iterator<Double> i = values.iterator();
		while(i.hasNext()){
			media += i.next();
		}
		return media/values.size();
	}
	
	public Double getVariance(List<Double> values){
		Double variance = new Double(0.0);
		
		Double media = new Double(getMean(values));
		
		Iterator<Double> i = values.iterator();
		while(i.hasNext()){
			variance += Math.pow((i.next() - media), 2);
		}
		
		return variance/(values.size() - 1);
	}
	
	public Double getStdDev(List<Double> values){
		return Math.sqrt(getVariance(values));
	}

	public void save_to_file(Double media, Double stdDev, String pathFile){
		PrintStream printFile = null;
		try {
			printFile = new PrintStream(new  File(pathFile));
			String line =  "$"+ media + " (\\pm"+ stdDev +")$";
			printFile.println(line);
			
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			System.out.println("error while saving to file on: save_to_file(Double media, Double stdDev, String pathFile); class: DataManipulation");
			e.printStackTrace();
		}
		finally{
			printFile.close();
		}
		
	}
	
	public void load_baseClassifiers_settings(String pathFile){
		Scanner scanner = null;
		final String markerBaseClassifier = "baseClassifiers";
		final String markerOptions = "options";
		final String markerNan = "nan";

		File file = new File(pathFile);

		try {
			scanner = new Scanner(file);
			ArrayList<String> baseClassifiers = new ArrayList<String>();
			ArrayList<List<String>> optionsClassifiers = new ArrayList<List<String>>();
			if (scanner.hasNext()) {
				String line = scanner.nextLine();
				if (line.equals(markerBaseClassifier)) {
					while (scanner.hasNext()
							&& !(line = scanner.nextLine()).equals(markerOptions)) {
						baseClassifiers.add(line.trim());
					}
				}
				if(line.equals(markerOptions)){
					while(scanner.hasNext()){
						line = scanner.nextLine().trim();
						String[] option = null;
						if(markerNan.equalsIgnoreCase(line)){
							option = new String[1];
							option[0] = "";
						}else{
							option = line.split(",");
						}
						optionsClassifiers.add(Arrays.asList(option));
					}
				}
				if (baseClassifiers.size() != optionsClassifiers.size()) {
					System.out
							.println("Num de classificadores e num de opções diferentes..");
					System.exit(1);
				}

				// it converts list to array
				this.baseClassifiers = baseClassifiers
						.toArray(new String[baseClassifiers.size()]);
//				System.out.println(this.baseClassifiers[0]);

				options = new String[optionsClassifiers.size()][];
				for (int i = 0; i < optionsClassifiers.size(); i++) {
					options[i] = new String[optionsClassifiers.get(i).size()];
					for (int j = 0; j < optionsClassifiers.get(i).size(); j++) {
						options[i][j] = optionsClassifiers.get(i).get(j);
					}
				}
				
				
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			scanner.close();
		}
		

	}

	public String[] getBaseClassifiers(){
		return baseClassifiers;
	}
	
	public String[][] getBaseClassifiersOptions(){
		return options;
	}
}
